import org.w3c.dom.*;

import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import java.io.*;
import java.util.*;

public class XMLStudentManager {
    // reader
    public static class MyXMLReader{
        private String filePath;
        private Document doc;
        public MyXMLReader(String filePath) {
            try {
                this.filePath = filePath;
                reload();
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                DocumentBuilder builder = factory.newDocumentBuilder();
                doc = builder.parse(new File(filePath));
            } catch (Exception e) {
                System.err.println(e.getMessage());
                e.printStackTrace();
            }
        }

        public void reload() {
            try {
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                DocumentBuilder builder = factory.newDocumentBuilder();
                File file = new File(filePath);

                if (file.exists()) {
                    doc = builder.parse(file);
                } else {
                    // 文件不存在时创建空文档
                    doc = builder.newDocument();
                    Element root = doc.createElement("Students");
                    doc.appendChild(root);
                }
            } catch (Exception e) {
                System.err.println("重新加载文档失败: " + e.getMessage());
                e.printStackTrace();
            }
        }

        // parse element
        private Student parseStudentElement(Element studentElement) {
            String id = getElementText(studentElement, "ID");
            String name = getElementText(studentElement, "Name");
            String gender = getElementText(studentElement, "Gender");
            String major = getElementText(studentElement, "Major");
            return new Student(id, name, gender, major);
        }
        // get text
        private String getElementText(Element parent, String tagName) {
            NodeList nodes = parent.getElementsByTagName(tagName);
            if (nodes.getLength() > 0) {
                return nodes.item(0).getTextContent();
            }
            return "";
        }
        // readAll
        public List<Student> readAllStudents() {
            if(doc == null) return null;
            List<Student> students = new ArrayList<>();
            NodeList studentNodes = doc.getElementsByTagName("Student");
            for(int i = 0; i < studentNodes.getLength(); i++) {
                Element studentElement = (Element) studentNodes.item(i);
                students.add(parseStudentElement(studentElement));
            }
            return students;
        }
        // get by id
        public Student getStudentById(String id) {
            if(doc == null) return null;
            NodeList studentNodes = doc.getElementsByTagName("Student");
            for (int i = 0; i < studentNodes.getLength(); i++) {
                Element studentElement = (Element) studentNodes.item(i);
                String studentId = getElementText(studentElement, "ID");
                if (studentId.equals(id)) {
                    return parseStudentElement(studentElement);
                }
            }
            return null;
        }
        // get by name
        public List<Student> getStudentByName(String name) {
            if(doc == null) return null;
            List<Student> result = new ArrayList<>();
            NodeList studentNodes = doc.getElementsByTagName("Student");
            for(int i = 0; i < studentNodes.getLength(); i++) {
                Element studentElement = (Element) studentNodes.item(i);
                String studentName = getElementText(studentElement, "Name");
                if(studentName.equals(name)) {
                    result.add(parseStudentElement(studentElement));
                }
            }
            return result;
        }
        // get by gender
        public List<Student> getStudentByGender(String gender) {
            if(doc == null) return null;
            List<Student> result = new ArrayList<>();
            NodeList studentNodes = doc.getElementsByTagName("Student");
            for(int i = 0; i < studentNodes.getLength(); i++) {
                Element studentElement = (Element) studentNodes.item(i);
                String studentGender = getElementText(studentElement, "Gender");
                if(studentGender.equals(gender)) {
                    result.add(parseStudentElement(studentElement));
                }
            }
            return result;
        }
        // get by major
        public List<Student> getStudentByMajor(String major) {
            if(doc == null) return null;
            List<Student> result = new ArrayList<>();
            NodeList studentNodes = doc.getElementsByTagName("Student");
            for(int i = 0; i < studentNodes.getLength(); i++) {
                Element studentElement = (Element) studentNodes.item(i);
                String studentMajor = getElementText(studentElement, "Major");
                if(studentMajor.equals(major)) {
                    result.add(parseStudentElement(studentElement));
                }
            }
            return result;
        }
    }
    // writer
    public static class MyXMLWriter {
        private String filePath;
        public MyXMLWriter(String filePath) {
            this.filePath = filePath;
        }
        // add a student
        public void addStudent(Student student) throws Exception{
            addStudents(Collections.singletonList(student));
        }
        // add students
        public void addStudents(List<Student> newStudents) throws Exception {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            // file
            File xmlFile = new File(filePath);
            Document doc;
            Element rootElement;
            if(xmlFile.exists()) {
                doc = builder.parse(xmlFile);
                rootElement = doc.getDocumentElement();
            } else {
                doc = builder.newDocument();
                rootElement = doc.createElement("Students");
                doc.appendChild(rootElement);
            }
            // add
            for(Student student : newStudents) {
                Element studentElement = createStudentElement(doc, student);
                rootElement.appendChild(studentElement);
            }
            // save
            saveDocument(doc);
        }
        public void updateStudent(Student student) throws Exception {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(new File(filePath));

            NodeList studentNodes = doc.getElementsByTagName("Student");
            for (int i = 0; i < studentNodes.getLength(); i++) {
                Element studentElement = (Element) studentNodes.item(i);
                String studentId = getElementText(studentElement, "ID");

                if (studentId.equals(student.getId())) {
                    // 更新现有学生信息
                    updateElementText(studentElement, "Name", student.getName());
                    updateElementText(studentElement, "Gender", student.getGender());
                    updateElementText(studentElement, "Major", student.getMajor());
                    break;
                }
            }
            // save document
            saveDocument(doc);
        }
        // create student element
        private Element createStudentElement(Document doc, Student student) {
            Element studentElement = doc.createElement("Student");
            addChildElement(doc, studentElement, "ID", student.getId());
            addChildElement(doc, studentElement, "Name", student.getName());
            addChildElement(doc, studentElement, "Gender", student.getGender());
            addChildElement(doc, studentElement, "Major", student.getMajor());
            return studentElement;
        }
        // add child element
        private void addChildElement(Document doc, Element parent, String tagName, String value) {
            Element elem = doc.createElement(tagName);
            elem.appendChild(doc.createTextNode(value));
            parent.appendChild(elem);
        }
        // update element text
        private void updateElementText(Element parent, String tagName, String newValue) {
            NodeList nodes = parent.getElementsByTagName(tagName);
            if (nodes.getLength() > 0) {
                nodes.item(0).setTextContent(newValue);
            }
        }
        // get element text
        private String getElementText(Element parent, String tagName) {
            NodeList nodes = parent.getElementsByTagName(tagName);
            if (nodes.getLength() > 0) {
                return nodes.item(0).getTextContent();
            }
            return "";
        }
        // save document
        private void saveDocument(Document doc) throws Exception {
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");

            DOMSource source = new DOMSource(doc);
            StreamResult result = new StreamResult(new File(filePath));
            transformer.transform(source, result);
        }

        //delete student
        public void deleteStudent(String id) throws Exception {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(new File(filePath));

            NodeList studentNodes = doc.getElementsByTagName("Student");
            for (int i = 0; i < studentNodes.getLength(); i++) {
                Element studentElement = (Element) studentNodes.item(i);
                String studentId = getElementText(studentElement, "ID");

                if (studentId.equals(id)) {
                    studentElement.getParentNode().removeChild(studentElement);
                    break;
                }
            }
            saveDocument(doc);
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String filePath = "MyStudentInfo.xml";  // 默认XML文件路径

        MyXMLReader reader = new MyXMLReader(filePath);
        MyXMLWriter writer = new MyXMLWriter(filePath);

        while (true) {
            System.out.println("\n学生信息管理系统");
            System.out.println("[1. 添加学生]");
            System.out.println("[2. 查询学生]");
            System.out.println("[3. 更新学生信息]");
            System.out.println("[4. 删除学生]");
            System.out.println("[5. 退出系统]");
            System.out.print("请选择操作: ");

            int choice = scanner.nextInt();
            scanner.nextLine();  // 消耗换行符

            try {
                switch (choice) {
                    case 1: // 添加学生
                        System.out.print("输入学生ID: ");
                        String id = scanner.nextLine();
                        System.out.print("输入姓名: ");
                        String name = scanner.nextLine();
                        System.out.print("输入性别: ");
                        String gender = scanner.nextLine();
                        System.out.print("输入专业: ");
                        String major = scanner.nextLine();

                        writer.addStudent(new Student(id, name, gender, major));
                        reader.reload();
                        System.out.println("学生添加成功!");
                        break;

                    case 2: // 查询学生分支
                        handleQueryOperations(scanner, reader);
                        break;

                    case 3: // 更新学生
                        System.out.print("输入要更新的学生ID: ");
                        String updateId = scanner.nextLine();
                        Student existing = reader.getStudentById(updateId);

                        if (existing != null) {
                            System.out.println("当前信息: " + existing);
                            System.out.print("输入新姓名 (留空保持不变): ");
                            String newName = scanner.nextLine();
                            System.out.print("输入新性别 (留空保持不变): ");
                            String newGender = scanner.nextLine();
                            System.out.print("输入新专业 (留空保持不变): ");
                            String newMajor = scanner.nextLine();

                            Student updated = new Student(
                                    updateId,
                                    newName.isEmpty() ? existing.getName() : newName,
                                    newGender.isEmpty() ? existing.getGender() : newGender,
                                    newMajor.isEmpty() ? existing.getMajor() : newMajor
                            );

                            writer.updateStudent(updated);
                            reader.reload();
                            System.out.println("信息更新成功!");
                        } else {
                            System.out.println("未找到该学生");
                        }
                        break;

                    case 4: // 删除学生
                        System.out.print("输入要删除的学生ID: ");
                        String deleteId = scanner.nextLine();
                        if (reader.getStudentById(deleteId) != null) {
                            writer.deleteStudent(deleteId);
                            reader.reload();
                            System.out.println("学生删除成功!");
                        } else {
                            System.out.println("未找到该学生");
                        }
                        break;

                    case 5: // 退出
                        System.out.println("系统已退出");
                        return;

                    default:
                        System.out.println("无效选择，请重新输入");
                }
            } catch (Exception e) {
                System.err.println("操作失败: " + e.getMessage());
            }
        }
    }

    private static void handleQueryOperations(Scanner scanner, MyXMLReader reader) {
        while (true) {
            System.out.println("\n查询学生");
            System.out.println("[1. 查询所有学生]");
            System.out.println("[2. 按ID查询学生]");
            System.out.println("[3. 按姓名查询学生]");
            System.out.println("[4. 按专业查询学生]");
            System.out.println("[5. 返回主菜单]");
            System.out.print("请选择查询方式: ");

            int queryChoice = scanner.nextInt();
            scanner.nextLine();  // 消耗换行符

            try {
                switch (queryChoice) {
                    case 1: // 查询所有学生
                        List<Student> allStudents = reader.readAllStudents();
                        if (allStudents != null && !allStudents.isEmpty()) {
                            System.out.println("\n所有学生信息:");
                            allStudents.forEach(System.out::println);
                        } else {
                            System.out.println("没有学生记录");
                        }
                        break;

                    case 2: // 按ID查询
                        System.out.print("输入要查询的学生ID: ");
                        Student student = reader.getStudentById(scanner.nextLine());
                        if (student != null) {
                            System.out.println("查询结果: " + student);
                        } else {
                            System.out.println("未找到该学生");
                        }
                        break;

                    case 3: // 按姓名查询
                        System.out.print("输入要查询的姓名: ");
                        List<Student> byName = reader.getStudentByName(scanner.nextLine());
                        printResult(byName);
                        break;

                    case 4: // 按专业查询
                        System.out.print("输入要查询的专业: ");
                        List<Student> byMajor = reader.getStudentByMajor(scanner.nextLine());
                        printResult(byMajor);
                        break;

                    case 5: // 返回主菜单
                        return;

                    default:
                        System.out.println("无效选择，请重新输入");
                }
            } catch (Exception e) {
                System.err.println("查询失败: " + e.getMessage());
            }
        }
    }

    //打印查询结果
    private static void printResult(List<Student> students) {
        if (students != null && !students.isEmpty()) {
            System.out.println("查询结果 (" + students.size() + " 条记录):");
            students.forEach(System.out::println);
        } else {
            System.out.println("未找到匹配记录");
        }
    }
}

